package com.sangeng.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sangeng.constants.SystemConstants;
import com.sangeng.domain.ResponseResult;
import com.sangeng.domain.entity.Menu;
import com.sangeng.domain.entity.RoleMenu;
import com.sangeng.domain.vo.MenuListVo;
import com.sangeng.domain.vo.MenuTreeListCheckedVo;
import com.sangeng.domain.vo.MenuTreeListVo;
import com.sangeng.domain.vo.MenuUpdateVo;
import com.sangeng.mapper.MenuMapper;
import com.sangeng.service.MenuService;
import com.sangeng.service.RoleMenuService;
import com.sangeng.utils.BeanCopyUtils;
import com.sangeng.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 菜单权限表(Menu)表服务实现类
 *
 * @author makejava
 * @since 2023-10-09 20:37:58
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RoleMenuService roleMenuService;
    /**
     * 根据用户id查询权限信息
     * @param id
     * @return
     */

    @Override
    public List<String> selectPermsByUserId(Long id) {
        //1.判断是否是管理员，若是，返回所有的权限
        if(SecurityUtils.isAdmin()){
            LambdaQueryWrapper<Menu> lqw=new LambdaQueryWrapper<>();
            //1.2 权限：菜单c,按钮f
            lqw.in(Menu::getMenuType, SystemConstants.MENU,SystemConstants.BUTTON);
            //1.3 状态正常的
            lqw.eq(Menu::getStatus,SystemConstants.MENU_STATUS_NORMAL);
            List<Menu> list = list(lqw);
            //1.4集合处理
            List<String> authorityList = list.stream()
                    .map(menu -> menu.getPerms())
                    .collect(Collectors.toList());
            return authorityList;
        }
        //否则根据用户id查询相应的权限
        return menuMapper.selectPermsByUserId(id);
    }
    /**
     * 获取动态路由表：父子菜单
     * @return
     */

    @Override
    public List<Menu> selectRouterMenuTreeByUserId(Long userId) {
        //判断是否是管理员，是管理员，返回所有目录m,菜单c，状态为正常的权限
        List<Menu> menuList=null;
        if(SecurityUtils.isAdmin()){
            LambdaQueryWrapper<Menu> lqw=new LambdaQueryWrapper<>();
            //1.2 权限：菜单c,目录m
            lqw.in(Menu::getMenuType, SystemConstants.MENU,SystemConstants.DIRECTORY);
            //1.3 状态正常的
            lqw.eq(Menu::getStatus,SystemConstants.MENU_STATUS_NORMAL);
            //1.4根据parentId和order_num排序
            lqw.orderByAsc(Menu::getParentId,Menu::getOrderNum);
            menuList = list(lqw);
        }else{
            //不是管理员，根据用户id查询权限表
            menuList=menuMapper.selectRouterMenuTreeByUserId(userId);
        }
        //查询菜单列表中为目录（parentId=0)中的菜单，并查询它们的子菜单来设置它们children属性
        List<Menu> finalMenuList = menuList;
        List<Menu> menuTree = menuList.stream().filter(menu -> menu.getParentId().equals(0L))
                .map(menu -> menu.setChildren(getChildrenList(menu, finalMenuList)))
                .collect(Collectors.toList());
        return menuTree;
    }

    /**
     *查询某目录的子菜单
     * @param menu
     * @param finalMenuList
     * @return
     */
    private List<Menu> getChildrenList(Menu menu, List<Menu> finalMenuList) {
        List<Menu> chilrenList = finalMenuList.stream()
                .filter(m -> m.getParentId().equals(menu.getId()))
                //还要递归查看子菜单是否还有子菜单
                .map(m->m.setChildren(getChildrenList(m,finalMenuList)))
                .collect(Collectors.toList());
        return chilrenList;
    }
    /**
     需要展示菜单列表，不需要分页。
     可以针对菜单名进行模糊查询
     也可以针对菜单的状态进行查询。
     菜单要按照父菜单id和orderNum进行排序
     * @param status
     * @param menuName
     * @return
     */
    @Override
    public ResponseResult<List<MenuListVo>> selectMenuList(Character status, String menuName) {
        LambdaQueryWrapper<Menu> lqw=new LambdaQueryWrapper<>();
        lqw.eq(status!=null,Menu::getStatus,status);
        lqw.like(StringUtils.hasText(menuName),Menu::getMenuName,menuName);
        lqw.orderByAsc(Menu::getParentId, Menu::getOrderNum);
        //查询数据
        List<Menu> list = list(lqw);
        //数据封装
        List<MenuListVo> menuListVos = BeanCopyUtils.copyBeanList(list, MenuListVo.class);
        return ResponseResult.okResult(menuListVos);
    }
    /**
     * 新增菜单
     * @param menu
     * @return
     */
    @Override
    public ResponseResult saveData(Menu menu) {
        save(menu);
        return ResponseResult.okResult();
    }
    /**
     * 根据id查询菜单表
     * @param id
     * @return
     */
    @Override
    public ResponseResult<MenuUpdateVo> getMenuById(Long id) {
        Menu menu = getById(id);
        MenuUpdateVo menuUpdateVo = BeanCopyUtils.copyBean(menu, MenuUpdateVo.class);
        return ResponseResult.okResult(menuUpdateVo);
    }
    /**
     * 更新数据
     * @param menu
     * @return
     */
    @Override
    public ResponseResult updateData(Menu menu) {
        //先判断提交过来的数据的parentId是否等于实体的id,
        // 要是相等，插入数据库中会有无限的循环，返回错误信息
        if(menu.getParentId().equals(menu.getId())){
            return ResponseResult.errorResult(500,SystemConstants.UPDATE_MENU_FAILED);
        }
        //更新数据
        updateById(menu);
        return ResponseResult.okResult();
    }
    /**
     * 能够删除菜单，但是如果要删除的菜单有子菜单则提示：存在子菜单不允许删除 并且删除失败。
     * @param menuId
     * @return
     */

    @Override
    public ResponseResult deleteDataById(Long menuId) {
        //查询该菜单是否有子菜单
        LambdaQueryWrapper<Menu> lqw=new LambdaQueryWrapper<>();
        lqw.eq(Menu::getParentId,menuId);
        List<Menu> list = list(lqw);
        if(list!=null&&list.size()>0){
            //有子菜单
            return ResponseResult.errorResult(500,SystemConstants.EXISTS_SUB_MENU);
        }
        //删除数据
        removeById(menuId);
        return ResponseResult.okResult();
    }
    /**
     * 获取菜单的列表树
     * @return
     */
    @Override
    public ResponseResult<List<MenuTreeListVo>> getMenuTreeList() {
        //将查询到的数据进行类型转换(孩子属性暂时置为null)
        List<Menu> list = list();
        List<MenuTreeListVo> menuList = list.stream().
                map(m -> new MenuTreeListVo(m.getId(), m.getMenuName(), m.getParentId(), null))
                .collect(Collectors.toList());
        //注意map函数需要有返回值，但是set方法并不会有返回值，所以需要设置相应的实体类的注解@Accessors(chain = true)

        List<MenuTreeListVo> collect = menuList.stream().filter(m -> m.getParentId().equals(0L))
                .map(menu -> menu.setChildren(getChildrenTreeList(menu, menuList)))
                .collect(Collectors.toList());

        return  ResponseResult.okResult(collect);
    }

    /**
     * 查询某一目录下的子目录
     * @param m
     * @param menuList
     * @return
     */
    private List<MenuTreeListVo> getChildrenTreeList(MenuTreeListVo m, List<MenuTreeListVo> menuList) {
        return menuList.stream()
                .filter(menu -> menu.getParentId().equals(m.getId()))
                //还要递归查看子菜单是否还有子菜单
                .map(menu->menu.setChildren(getChildrenTreeList(menu,menuList)))
                .collect(Collectors.toList());
    }
    /**
     * 根据角色id查询权限树列表
     * @param id
     * @return
     */
    @Override
    public ResponseResult<MenuTreeListCheckedVo> getRoleMenuTreeList(Long id) {
        //先在角色权限表中查询当前角色对应的权限列表
        LambdaQueryWrapper<RoleMenu> lqw=new LambdaQueryWrapper<>();
        lqw.eq(RoleMenu::getRoleId,id);
        List<RoleMenu> list = roleMenuService.list(lqw);
        List<Long> menuIds = list.stream().map(rm -> rm.getMenuId())
                .collect(Collectors.toList());
        //然后查询菜单表中权限树列表
        ResponseResult<List<MenuTreeListVo>> menuTreeList = getMenuTreeList();
        List<MenuTreeListVo> data = menuTreeList.getData();
        return ResponseResult.okResult(new MenuTreeListCheckedVo(data,menuIds));
    }


}
